#include "backuptask.h"
#include <QSqlError>

BackupTask::BackupTask()
{
    taskType = BackupTask::Backup;
}

BackupTask::BackupTask(quint32 taskId)
{
    this->taskId = taskId;
    taskType = BackupTask::Backup;

    QSqlQuery query;
    query.prepare("SELECT task FROM tasks WHERE id = :task_id");
    query.bindValue(":task_id", taskId);
    query.exec();
    if(query.next()) {
        QByteArray array = query.value(0).toByteArray();
        QDataStream stream(&array, QIODevice::ReadOnly);

        this->unserialize(stream);
    }
}

BackupTask::~BackupTask()
{
}

void BackupTask::serialize(QDataStream &out)
{
    out << (int)backupType
        << (int)targetType
        << (int)verificationType
        << (int)compressionType
        << archived
        << periodic
        << sourcePath
        << targetPath
        << remoteHost
        << remoteLogin
        << remotePassword
        << remoteTargetDir
        << nextRun
        << interval;
}

void BackupTask::unserialize(QDataStream &in)
{
    quint32 tmp;
    in >> tmp;
    backupType = (BackupType)tmp;
    in >> tmp;
    targetType = (TargetType)tmp;
    in >> tmp;
    verificationType = (VerificationType)tmp;
    in >> tmp;
    compressionType = (CompressionType)tmp;

    in >> archived
       >> periodic
       >> sourcePath
       >> targetPath
       >> remoteHost
       >> remoteLogin
       >> remotePassword
       >> remoteTargetDir
       >> nextRun
       >> interval;
}

void BackupTask::createTask()
{
    QByteArray array;
    QDataStream stream(&array, QIODevice::WriteOnly);

    this->serialize(stream);

    QSqlQuery query;
    query.prepare("INSERT INTO tasks(task) "
                  "VALUES (:task);"
                  );

    query.bindValue(":task", array);
    query.exec();

    query.exec("SELECT last_insert_rowid()");
    query.next();
    this->taskId = query.value(0).toUInt();
}

void BackupTask::updateTask()
{
    QByteArray array;
    QDataStream stream(&array, QIODevice::WriteOnly);

    this->serialize(stream);

    QSqlQuery query;
    query.prepare("UPDATE tasks "
                  "SET task = :task "
                  "WHERE id = :id"
                  );

    query.bindValue(":id", this->taskId);
    query.bindValue(":task", array);

    query.exec();
    qDebug() << query.lastError().text();
}

void BackupTask::deleteTask()
{
    foreach(QDateTime timestamp, this->getInstances()) {
        deleteInstance(timestamp);
    }

    QSqlQuery query;
    query.prepare("DELETE FROM tasks "
                  "WHERE id = :id"
                  );

    query.bindValue(":id", this->taskId);

    query.exec();
}

void BackupTask::saveInstance(QDateTime timestamp, quint32 instance_parent)
{
    QSqlQuery query;
    query.prepare("INSERT INTO instances(task_id, timestamp, instance_parent) "
                  "VALUES (:task_id, :timestamp, :instance_parent);"
                  );

    query.bindValue(":task_id", taskId);
    query.bindValue(":timestamp", timestamp.toTime_t());
    query.bindValue(":instance_parent", instance_parent);

    query.exec();
}

void BackupTask::deleteInstance(QDateTime timestamp)
{
    QString path = QString("%1/backup/%2")
            .arg(this->getTargetPath())
            .arg(timestamp.toTime_t());

    FileUtils::removeDir(path);

    QSqlQuery query;
    query.prepare("DELETE FROM instances "
                  "WHERE task_id = :id AND timestamp = :timestamp"
                  );

    query.bindValue(":id", this->taskId);
    query.bindValue(":timestamp", timestamp.toTime_t());

    query.exec();
}

QList<QDateTime> BackupTask::getInstances()
{
    QList<QDateTime> list;
    QSqlQuery query;
    query.prepare("SELECT(timestamp) FROM instances WHERE task_id = :task_id;");
    query.bindValue(":task_id", taskId);

    query.exec();
    while(query.next()) {
        list.append(QDateTime::fromTime_t(query.value(0).toUInt()));
    }

    return list;
}

quint32 BackupTask::getInstanceParent(QDateTime timestamp)
{
    QSqlQuery query;
    query.prepare("SELECT(instance_parent) FROM instances WHERE task_id = :task_id AND timestamp = :timestamp;");
    query.bindValue(":task_id", getTaskId());
    query.bindValue(":timestamp", timestamp.toTime_t());
    query.exec();
    if(query.next()) {
        return query.value(0).toUInt();
    } else { //Should not happen under normal circumstances
        qDebug() << "BackupTask::getInstanceParent() used with invalid timestamp";
        return 0;
    }
}

void BackupTask::setInstanceSize(QDateTime timestamp, quint64 size)
{
    QSqlQuery query;
    query.prepare("UPDATE instances SET size = :size WHERE task_id = :task_id AND timestamp = :timestamp;");
    query.bindValue(":task_id", getTaskId());
    query.bindValue(":timestamp", timestamp.toTime_t());
    query.bindValue(":size", size);
    query.exec();
}

quint64 BackupTask::getInstanceSize(QDateTime timestamp)
{
    QSqlQuery query;
    query.prepare("SELECT size FROM instances WHERE task_id = :task_id AND timestamp = :timestamp;");
    query.bindValue(":task_id", getTaskId());
    query.bindValue(":timestamp", timestamp.toTime_t());
    query.exec();
    if(query.next()) {
        return query.value(0).toULongLong();
    } else {
        return 0;
    }
}

bool BackupTask::instanceHasChildren(QDateTime timestamp)
{
    QSqlQuery query;
    query.prepare("SELECT * FROM instances WHERE task_id = :task_id AND instance_parent = :instance_parent;");
    query.bindValue(":task_id", getTaskId());
    query.bindValue(":instance_parent", timestamp.toTime_t());
    query.exec();
    if(query.next()) {
        return true;
    } else {
        return false;
    }
}

void BackupTask::setRemoteOptions(QString host, QString login, QString pass, QString dir)
{
    this->remoteHost = host;
    this->remoteLogin = login;
    this->remotePassword = pass;
    this->remoteTargetDir = dir;
}

void BackupTask::SetupNewNextRun()
{
    this->nextRun = QDateTime::currentDateTime().addSecs(interval * 3600);
    this->updateTask();
}
